--[[
    划分牌等级
s：AA, KK
a: AKs,AKo,QQ,JJ
b: AQs,AJs,ATs,KQs, KJs,KTs,QJs,QTs,JTs,A9s,T9s
   KQo,AQo,KQo,AJo,TT,99,88,77,66,

c: A8s,A7s,A6s,A5s,A4s,A3s,A2s,98s,87s,76s,65s,K9s,Q9s,J9s
55,44,33,22,ATo,KJo,QJo,

d: K8s,Q8s,J8s,T8s,97s,86s,75s,
KTo,QTo,JTo,A9o,K9o,Q9o,J9o,T9o,A8o,A7o

--]]


local cjson = require("cjson")

local math_random = math.random

local M = class("cards_oper")

function M:ctor()
    --不同花色表
    self.map_cards_lv = {
        --2,3,4,5,6,7,8,9,T,J,Q,K,A
        {4,0,0,0,0,0,0,0,0,0,0,0,0},  --2
        {0,4,0,0,0,0,0,0,0,0,0,0,0},  --3
        {0,0,4,0,0,0,0,0,0,0,0,0,0},  --4
        {0,0,8,4,0,0,0,0,0,0,0,0,0},  --5
        {0,0,9,8,3,0,0,0,0,0,0,0,0},  --6
        {0,0,0,9,8,3,0,0,0,0,0,0,0},  --7
        {0,0,0,9,9,8,3,0,0,0,0,0,0},  --8
        {0,0,0,0,0,9,8,3,0,0,0,0,0},  --9
        {0,0,0,0,0,9,8,5,3,0,0,0,0},  --T
        {0,0,0,0,0,0,0,5,5,2,0,0,0},  --J
        {0,0,0,0,0,0,0,5,5,7,2,0,0},  --Q
        {0,0,0,0,0,0,9,8,5,6,3,1,0},  --K
        {7,7,7,7,7,5,5,5,5,3,3,2,1},  --A
    }
    --同花色表
    self.map_cards_lv2 = {
        --2,3,4,5,6,7,8,9,T,J,Q,K,A
        {4,0,0,0,0,0,0,0,0,0,0,0,0},  --2
        {0,4,0,0,0,0,0,0,0,0,0,0,0},  --3
        {0,0,4,0,0,0,0,0,0,0,0,0,0},  --4
        {0,0,8,4,0,0,0,0,0,0,0,0,0},  --5
        {0,0,9,4,3,0,0,0,0,0,0,0,0},  --6
        {0,0,0,5,4,3,0,0,0,0,0,0,0},  --7
        {0,0,0,9,5,4,3,0,0,0,0,0,0},  --8
        {0,0,0,0,4,5,4,3,0,0,0,0,0},  --9
        {0,0,0,0,0,9,8,3,3,0,0,0,0},  --T
        {0,0,0,0,0,0,0,5,3,2,0,0,0},  --J
        {0,0,0,0,0,0,0,5,3,3,2,0,0},  --Q
        {0,0,0,0,0,0,0,5,3,3,3,1,0},  --K
        {4,4,4,4,4,4,4,3,3,3,3,2,1},  --A
    }

    --成牌类型

    --听牌类型

    --操作阶段

    self:register()
end

function M:register()
    local config_path = g.getenv("root") .. "config/" --配置文件所在目录
    local path = config_path.."robot_preflop_cfg.lua"
    self.preflop_cfg = dofile(path)
    for _, v in pairs(self.preflop_cfg) do
        v.oper = cjson.decode(v.oper)
    end
    --翻牌后的操作
    local path = config_path.."robot_flop_cfg.lua"
    self.flop_cfg = dofile(path)
    for _, v in pairs(self.flop_cfg) do
        v.oper = cjson.decode(v.oper)
    end
end

-- 计算手牌等级
function M:getCardsLv(cards)
    --先取花色
    local colors = {
        cards[1] & 0xf0,
        cards[2] & 0xf0,
    }
    local values = {
        cards[1] & 0x0f,
        cards[2] & 0x0f,
    }
    local lv = 5
    if colors[1] == colors[2] then
        lv = self.map_cards_lv2[values[1]%16 - 1][values[2]%16 - 1]
    else
        lv = self.map_cards_lv[values[1]%16 - 1][values[2]%16 - 1]
    end

    if lv == 0 or lv > 5 then
        lv = 5
    end
    return lv
end

--返回操作
function M:getBetChip(user)
    local chip = 0
    if g.desk:getStage() == g.desk.s_stage_preflop then
        chip = self:getBetChipPreflop(user)
    else
        chip = self:getBetChipFlop(user)
    end
    local user_stage_bet = user:getStageBet()
    local user_chip = user:getChip()
    if user_stage_bet + chip > g.desk.stage_bet then
        if user_stage_bet + chip < g.desk.min_raise_bet then
            chip = g.desk.min_raise_bet - user_stage_bet
        end
    elseif chip > 0 and user_stage_bet + chip < g.desk.stage_bet then
        chip = g.desk.stage_bet - user_stage_bet
    end
    if chip == 0 then
        if g.desk.stage_bet - user_stage_bet ~= 0 then
            chip = -1
        end
    elseif chip == -1 then
        if g.desk.stage_bet - user_stage_bet == 0 then
            chip = 0
        end
        --如果已下注了很多剩下一点点就不要弃牌了
        if user:getSeatBet() > user_chip*5 then
            chip = user_chip
        end
        if g.desk.stage_bet - user_stage_bet <= user_stage_bet*0.2 then
            --差一点就可以跟注
            chip = g.desk.stage_bet - user_stage_bet
        end
    end
    if chip > user_chip then
        chip = user_chip
    end
    if chip < user_chip then
        if user_chip - chip < user_chip * 0.7 then
            --剩下太少了直接allin
            chip = user_chip
        end
    end

    return chip
end

function M:getBetChipPreflop(user)
    local desk = g.desk
    local cards = user:getCards()
    local personality = user:getPersonality() --性格
    local giveup_num = user:getGiveupNum() --翻牌前弃牌次数
    local lv = self:getCardsLv(cards)
    local seat_name = g.desk:getSeatName(user)
    local cfg = {}
    local chip = 0
    local anger = 10
    if giveup_num > 1 then
        anger = 3*anger
    end
    local tb_personality_add = {
        10 + anger,
        math_random(0, 10) + anger,
        0 + anger,
        0 + anger,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    }
    local personality_add = tb_personality_add[personality]

    for _, v in pairs(self.preflop_cfg) do
        if v.sid == seat_name and lv == v.cards_lv then
            cfg = v.oper
            break
        end
    end
    --g.log:debug("11111getBetChip: ",  desk.stage_bet, desk.bb)
    local num = math_random(1, 100)
    num = num - personality_add --这个是个性加成
    if num < 1 then num = 1 end
    if desk.stage_bet <= desk.bb then
        --第一轮或是没加注前
        local opers = cfg.round1
        for _, oper in pairs(opers) do
            local bb_rate = oper.bb_rate
            if oper.rate[2] >= num and num > oper.rate[1] then
                --具体的操作 bb_rate = -1 弃牌， 1跟 2+加注到盲注位数, 100 allin
                if bb_rate == -1 then
                    chip = -1
                elseif bb_rate == 100 then
                    chip = user:getChip()
                elseif bb_rate == 1 then
                    chip = desk.stage_bet - user:getStageBet()
                elseif bb_rate > 1 then
                    chip = desk.bb * bb_rate
                end
                --g.log:debug("1getBetChip: ",  bb_rate)
                return chip
            end
        end
    else
        --加注后的操作
        local opers = cfg.round2
        for _, oper in pairs(opers) do
            if oper.rate[2] >= num and num > oper.rate[1] then
                --具体的操作
                local bb_rate = oper.bb_rate
                if bb_rate == -1 then
                    chip = -1
                elseif bb_rate == 100 then
                    chip = user:getChip()
                elseif bb_rate == 1 then
                    chip = desk.stage_bet - user:getStageBet()
                elseif bb_rate == 2 then
                    --反加注
                    chip = desk.min_raise_bet + desk.last_raise_bet
                elseif bb_rate > 2 then
                    chip = desk.bb * bb_rate
                end
                --g.log:debug("2getBetChip: ", bb_rate)
                return chip
            end
        end
    end

    return chip
end

--翻牌后的操作
function M:getBetChipFlop(user)
    local desk = g.desk
    local num = math_random(1, 100)

    local cfg = {}
    local chip = 0
    local ch_id = self:getChCardKind(user)
    for _, v in pairs(self.flop_cfg) do
        if v.type == "ch" and ch_id == v.cards_lv then
            cfg = v.oper
            break
        end
    end
    local ti_id = self:getTiCardKind(user)
    for _, v in pairs(self.flop_cfg) do
        if v.type == "ti" and ti_id == v.cards_lv then
            cfg = v.oper
            break
        end
    end

    if desk.stage_bet <= desk.bb then
        --第一轮或是没加注前
        local opers = cfg.round1
        for _, oper in pairs(opers) do
            if oper.rate[2] >= num and num > oper.rate[1] then
                --具体的操作 bb_rate = -1 弃牌， 1跟 2+加注到盲注位数, 100 allin
                local bb_rate = oper.bb_rate
                if bb_rate == -1 then
                    chip = -1
                elseif bb_rate == 100 then
                    chip = user:getChip()
                elseif bb_rate == 0 then
                    chip = desk.stage_bet - user:getStageBet()
                elseif bb_rate >= 1 then
                    chip = desk.min_raise_bet * bb_rate
                end
                g.log:debug("1getBetChipFlop: ",  bb_rate)
                return chip
            end
        end
    else
        --加注后的操作
        local opers = cfg.round2
        for _, oper in pairs(opers) do
            if oper.rate[2] >= num and num > oper.rate[1] then
                --具体的操作
                local bb_rate = oper.bb_rate
                if bb_rate == -1 then
                    chip = -1
                elseif bb_rate == 100 then
                    chip = user:getChip()
                elseif bb_rate == 0 then
                    chip = desk.stage_bet - user:getStageBet()
                elseif bb_rate == 1 then
                    --反加注
                    chip = desk.min_raise_bet + desk.last_raise_bet
                elseif bb_rate > 1 then
                    chip = desk.min_raise_bet * bb_rate
                end
                g.log:debug("2getBetChipFlop: ",  bb_rate)
                return chip
            end
        end
    end
    if chip > user:getChip() then
        chip = user:getChip()
    end
    return chip
end

function M:getColor(card)
    return card & 0xf0
end

function M:getValue(card)
    return card & 0x0f
end

--听牌类型
function M:getChCardKind(user)
    local kind = user:getKind() --这个是包公牌的牌型
    local cards = user:getCards()
    local is_pair = false
    if self:getValue(cards[1]) == self:getValue(cards[2]) then
        --手牌是对子
        is_pair = true
    end
    if kind < 4  then
        if is_pair then
            return kind
        end
        return 1
    end

    return kind
end

--听牌类型
function M:getTiCardKind(user)
    local cards = user:getCards()
    local common_cards = g.desk.common_cards
    --先取花色
    local colors = {
        cards[1] & 0xf0,
        cards[2] & 0xf0,
    }
    local values = {
        cards[1] & 0x0f,
        cards[2] & 0x0f,
    }

    for k, v in pairs(common_cards) do
        table.insert(colors, self:getColor(v))
        table.insert(values, self:getValue(v))
    end
    local function isTingFlush(colors)
        if #values < 4 then return false end
        local arr = {}
        for k, v in pairs(colors) do
            arr[v] = arr[v] and arr[v]+1 or 1
        end
        for k, v in pairs(arr) do
            if v >= 4 then
                return true
            end
        end
        return false
    end

    local function isTingStraight(values)
        if #values < 4 then return false end
        table.sort(values)
        if values[1]+1 == values[2] and values[2]+1 == values[3] and values[3]+1 == values[4] then
            return true
        end
        local len = #values
        if values[len]-1 == values[len-1] and values[len-1]-1 == values[len-2] and values[len-2]-1 == values[len-3] then
            return true
        end
        return false
    end

    if isTingFlush(colors) then
        return 1

    end
    if isTingStraight(values) then
        return 2
    end

    return 0
end

return M